#ifndef ___fat32_transacciones_funciones

#define ___fat32_transacciones_funciones 1

#include <stdlib.h>

#include "f32_trns.c"
#include "f32_trnc.c"
#include "f32_tfa1.c"

void fat32_crear_transaccion(int (*) (unsigned int, void *, void **, int (**) (unsigned int, int, unsigned char, void *, void **)),
                                                                                                                        void *, unsigned int);
void fat32_procesar_transacciones(void);
void fat32_terminar_transaccion(unsigned int);
void fat32_crear_operacion(unsigned int, unsigned char (*) (unsigned int, void *, void **), void *, unsigned int);
void fat32_quitar_operacion(unsigned int);

void fat32_crear_transaccion (int (* handlerInicial) (unsigned int, void *, void **,
                                                      int (**) (unsigned int, int, unsigned char, void *, void **)),
                              void * datosIniciales, unsigned int cantidadDatos) {
  fat32_transaccion_no_ejecutada nuevaTransaccion;
  nuevaTransaccion.handler = handlerInicial;
  if (cantidadDatos) {
    nuevaTransaccion.datos = malloc(cantidadDatos);
    memcpy(nuevaTransaccion.datos, datosIniciales, cantidadDatos);
  } else
    nuevaTransaccion.datos = NULL;
  fat32_insertar_transaccion_en_cola_pendientes(nuevaTransaccion);
}

void fat32_procesar_transacciones (void) {
  if (fat32_transacciones.primeraPendiente) {
    fat32_transaccion_no_ejecutada trans = fat32_tomar_primera_transaccion_pendiente();
    fat32_crear_nueva_transaccion_en_proceso(trans);
    return;
  }
  if (fat32_transacciones.actualEnProceso) {
    if (fat32_saltear_transacciones_bloqueadas()) return; // si no hay transacciones disponibles...
    fat32_procesar_transaccion(&((fat32_transacciones.actualEnProceso) -> transaccion));
    fat32_transacciones.actualEnProceso = (fat32_transacciones.actualEnProceso) -> siguiente;
    return;
  }
}

void fat32_terminar_transaccion (unsigned int transaccion) {
  struct fat32_nodo_trans * trns = fat32_buscar_nodo_transaccion(transaccion);
  if (!trns) return;
  struct fat32_nodo_trans * trns_ant = fat32_buscar_nodo_transaccion_anterior(trns);
  fat32_limpiar_datos_transaccion(transaccion);
  trns_ant -> siguiente = trns -> siguiente;
  if (fat32_transacciones.actualEnProceso == trns)
    fat32_transacciones.actualEnProceso = trns -> siguiente;
  if (fat32_transacciones.actualEnProceso == trns)
    fat32_transacciones.actualEnProceso = NULL;
  free(trns);
}

void fat32_crear_operacion (unsigned int transaccion, unsigned char (* handler) (unsigned int, void *, void **), void * datosEntrada,
                            unsigned int cantidadDatos) {
  struct fat32_nodo_trans * trans = fat32_buscar_nodo_transaccion(transaccion);
  if (!trans) return;
  if ((trans -> transaccion).tieneOperacion) return;
  (trans -> transaccion).tieneOperacion = 1;
  fat32_operacion oper;
  oper.estado = 0;
  oper.handler = handler;
  if (cantidadDatos) {
    oper.datosEntrada = malloc(cantidadDatos);
    memcpy(oper.datosEntrada, datosEntrada, cantidadDatos);
  } else
    oper.datosEntrada = NULL;
  oper.datosSalida = NULL;
  (trans -> transaccion).operacion = oper;
}

void fat32_quitar_operacion (unsigned int transaccion) {
  struct fat32_nodo_trans * trans = fat32_buscar_nodo_transaccion(transaccion);
  if (!trans) return;
  if (!(trans -> transaccion).tieneOperacion) return;
  if ((trans -> transaccion).operacion.datosEntrada) free((trans -> transaccion).operacion.datosEntrada);
  (trans -> transaccion).tieneOperacion = 0;
}

#endif